package com.zone.mybatis.datasource.pooled;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * @author: zongzi
 * @description: TODO
 * @date: 2023/12/25
 */
public class PooledConnection implements InvocationHandler {
    private static final String CLOSE = "close";
    private static final Class<?>[] IFACES = new Class[]{Connection.class};

    // 真实的连接对象
    private Connection realConnection;
    // 代理的连接对象
    private Connection proxyConnection;
    // 创建连接所使用时间
    private long cratedTimestamp;
    // 最后使用时间
    private long lastUsedTimeStamp;
    // 检出时间
    private long checkoutTimeStamp;

    // 数据源
    private PooledDataSource dataSource;

    // 是否有效
    private boolean valid;


    public PooledConnection(Connection connection, PooledDataSource dataSource) {
        this.realConnection = connection;
        this.dataSource = dataSource;
        this.cratedTimestamp = System.currentTimeMillis();
        this.lastUsedTimeStamp = System.currentTimeMillis();
        this.proxyConnection = (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(), IFACES, this);
        this.valid = true;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 关闭方法将connection放入连接池中
        if (CLOSE.hashCode() == method.getName().hashCode() && CLOSE.equals(method.getName())) {
            dataSource.pushConnection(this);
            return null;
        } else {
            return method.invoke(realConnection, args);
        }
    }

    public PooledDataSource getDataSource() {
        return dataSource;
    }

    public void invalidate() {
        this.valid = false;
    }

    public boolean isValid() {
        try {
            return valid && this.realConnection != null && this.realConnection.isValid(20);
        } catch (SQLException e) {
            return false;
        }
    }

    public Connection getRealConnection() {
        return realConnection;
    }

    public Connection getProxyConnection() {
        return proxyConnection;
    }

    public long getCratedTimestamp() {
        return cratedTimestamp;
    }

    public long getLastUsedTimeStamp() {
        return lastUsedTimeStamp;
    }

    public void setLastUsedTimeStamp(long lastUsedTimeStamp) {
        this.lastUsedTimeStamp = lastUsedTimeStamp;
    }

    public long getCheckoutTimeStamp() {
        return System.currentTimeMillis() - checkoutTimeStamp;
    }

    public void setCheckoutTimeStamp(long checkoutTimeStamp) {
        this.checkoutTimeStamp = checkoutTimeStamp;
    }
}
